package dao

import (
	"context"
	"errors"
	"fmt"
	"gorm.io/gorm"
	"log"
	"strconv"
)

var ErrRecordNotFound = fmt.Errorf("找不到对应记录")

const PageSize = 1000

type TranslationDao interface {
	//GetAllTranslationWithElementsId 输出后台系统的格式
	GetAllTranslationWithElementsId(ctx context.Context, ids ...string) ([]*Translation, error)
	GetAllElementsByLocale(ctx context.Context, locale string, ids ...string) ([]*Translation, error)
	Insert(ctx context.Context, translation Translation) error
	Update(ctx context.Context, translation Translation) error
	Delete(ctx context.Context, translation Translation) error
	IsExist(ctx context.Context, elementID, locale string) error
	BatchTranslation(ctx context.Context, translations []Translation) error
}

type GormTranslationDao struct {
	db *gorm.DB
}

func (g *GormTranslationDao) BatchTranslation(ctx context.Context, translations []Translation) error {
	if len(translations) == 0 {
		return nil
	}
	// 开始事务
	tx := g.db.WithContext(ctx).Begin()
	if tx.Error != nil {
		return fmt.Errorf("开始事务失败: %w", tx.Error)
	}
	// 使用 GORM 的 Create 方法进行批量插入
	result := tx.Create(&translations)
	if result.Error != nil {
		// 如果插入失败，回滚事务
		tx.Rollback()
		return fmt.Errorf("批量插入失败: %w", result.Error)
	}
	if result.RowsAffected != int64(len(translations)) {
		// 如果部分记录插入失败，回滚事务
		tx.Rollback()
		return fmt.Errorf("部分记录插入失败，插入了 %d 条记录，期望插入 %d 条记录", result.RowsAffected, len(translations))
	}
	// 提交事务
	if err := tx.Commit().Error; err != nil {
		return fmt.Errorf("提交事务失败: %w", err)
	}
	return nil
}

func (g *GormTranslationDao) IsExist(ctx context.Context, elementID, locale string) error {
	// 尝试将 elementID 转换为整数，若失败则返回错误
	id, err := strconv.Atoi(elementID)
	if err != nil {
		return fmt.Errorf("invalid elementID: %w", err)
	}

	// 执行数据库查询
	var translation Translation
	result := g.db.WithContext(ctx).First(&translation, "element_id = ? AND locale = ?", id, locale)

	// 检查查询结果
	if result.Error != nil {
		if errors.Is(result.Error, gorm.ErrRecordNotFound) {
			return ErrRecordNotFound
		}
		// 其他数据库错误返回具体错误信息
		return fmt.Errorf("database query failed: %w", result.Error)
	}

	// 如果查询成功且记录存在，返回 true
	return nil
}

func NewTranslationDao(db *gorm.DB) TranslationDao {
	return &GormTranslationDao{db: db}
}
func (g *GormTranslationDao) Insert(ctx context.Context, translation Translation) error {
	if tx := g.db.WithContext(ctx).Save(&translation); tx.RowsAffected != 1 {
		log.Printf("插入失败: %v", tx.Error)
		return tx.Error
	}
	return nil
}

func (g *GormTranslationDao) Update(ctx context.Context, translation Translation) error {
	result := g.db.WithContext(ctx).
		Model(&Translation{}).
		Where("element_id = ? AND locale = ?", translation.ElementID, translation.Locale).
		Updates(map[string]interface{}{
			"content": translation.Content,
		})

	if result.RowsAffected == 0 {
		log.Printf("插入失败: %v", result.Error)
		return ErrRecordNotFound
	}
	return result.Error
}

func (g *GormTranslationDao) Delete(ctx context.Context, translation Translation) error {
	if rs := g.db.WithContext(ctx).Delete(&Translation{ElementID: translation.ElementID, Locale: translation.Locale}); rs.RowsAffected != 1 {
		log.Printf("删除失败: %v", rs.Error)
		return ErrRecordNotFound
	}
	return nil
}

func (g *GormTranslationDao) GetAllTranslationWithElementsId(ctx context.Context, ids ...string) ([]*Translation, error) {
	var translations []*Translation
	if len(ids) == 0 {
		return nil, nil
	}

	for i := 0; i < len(ids); i += PageSize {
		end := i + PageSize
		if end > len(ids) {
			end = len(ids)
		}

		batchIDs := ids[i:end]
		var batchTranslations []*Translation
		err := g.db.WithContext(ctx).Where("element_id IN ?", batchIDs).Find(&batchTranslations).Error
		if err != nil {
			return nil, err
		}
		translations = append(translations, batchTranslations...)
	}
	return translations, nil
}

func (g *GormTranslationDao) GetAllElementsByLocale(ctx context.Context, locale string, ids ...string) ([]*Translation, error) {
	var translations []*Translation
	if len(ids) == 0 {
		return nil, nil
	}

	for i := 0; i < len(ids); i += PageSize {
		end := i + PageSize
		if end > len(ids) {
			end = len(ids)
		}
		batchIDs := ids[i:end]
		var batchTranslations []*Translation
		err := g.db.WithContext(ctx).Where("element_id IN ? And locale = ?", batchIDs, locale).Find(&batchTranslations).Error
		if err != nil {
			return nil, err
		}
		translations = append(translations, batchTranslations...)
	}
	return translations, nil
}

type Translation struct {
	ElementID int    `gorm:"primaryKey;column:element_id;type:int" json:"element_id"`
	Locale    string `gorm:"primaryKey;column:locale;type:varchar(10);not null" json:"locale"`
	Content   string `gorm:"type:text;not null" json:"content"`
}

func (Translation) TableName() string {
	return "translations"
}
